package com.ityls.shoping_order_customer_api.util;

import lombok.SneakyThrows;
import org.jose4j.json.JsonUtil;
import org.jose4j.jwa.AlgorithmConstraints;
import org.jose4j.jwk.RsaJsonWebKey;
import org.jose4j.jws.AlgorithmIdentifiers;
import org.jose4j.jws.JsonWebSignature;
import org.jose4j.jwt.JwtClaims;
import org.jose4j.jwt.consumer.JwtConsumer;
import org.jose4j.jwt.consumer.JwtConsumerBuilder;

import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.HashMap;
import java.util.Map;

public class JwtUtils {
    // 公钥
    public final static String PUBLIC_JSON = "{\"kty\":\"RSA\",\"n\":\"kkMFB482qG5cjMouvhn0ZuUwTtLvRsI3Q3CoIOcphHwFddggJpXCVno4nDNBoB74OwFn1cncIvsuUC2b7U1U0V3ra9EJnPd1xbitXst0Yd6CTKh9aDRBNAu0Hrq-BhF_wUqzLzzMLnM5XTbwq0Et9BFkwqCaBUfTJ_qco0UuGRmpeeqEIVZC0IxfSUszQQcgkkMicfCBVfvFzdEm8MHN0e9NX65Ae_rnMUCaGW3122tq8UYoBp5SZ6jwoNw2I2xCda3DHu3WYXhjx2VHd2B-C45jVDs77J_2w7fmYpXsH2WL_axe3m_e8P7UEt6mxVnRtevIdVIlv51Wnls5DJw1Aw\",\"e\":\"AQAB\"}\n";
    // 私钥
    public final static String PRIVATE_JSON = "{\"kty\":\"RSA\",\"n\":\"kkMFB482qG5cjMouvhn0ZuUwTtLvRsI3Q3CoIOcphHwFddggJpXCVno4nDNBoB74OwFn1cncIvsuUC2b7U1U0V3ra9EJnPd1xbitXst0Yd6CTKh9aDRBNAu0Hrq-BhF_wUqzLzzMLnM5XTbwq0Et9BFkwqCaBUfTJ_qco0UuGRmpeeqEIVZC0IxfSUszQQcgkkMicfCBVfvFzdEm8MHN0e9NX65Ae_rnMUCaGW3122tq8UYoBp5SZ6jwoNw2I2xCda3DHu3WYXhjx2VHd2B-C45jVDs77J_2w7fmYpXsH2WL_axe3m_e8P7UEt6mxVnRtevIdVIlv51Wnls5DJw1Aw\",\"e\":\"AQAB\",\"d\":\"MleyG_t9zzSJU4Zl11X8qwv4-DCfXkYMGoDkxcp7HlhH0tuMmWtTpEtWP-FelbwDKeAeetYLmNjHBJ7mPCQxbQz8MrSVL_t3BJK_zdCOov8g7zzRSXQu-ziKC0ewj0sno4LQMRKmnthXJs_5v6BkLk1sVpdL3ERwGCMpFgOCTe3jhhhJw4i7VeSLhFZq3p7D24_sGV5klhc5oo8GelLQtA9Kk2zaTHz_OfPH8eCtS7u3PQacI6CpBFYzBxqck-lm-7cEoyGhUWRbAOjr54CEk1B7tGVept9I65_lIkp6UQ1qjRr3WzbfaMz953-C0L4WoPhCzUxwNHmzY2IfmoF_lQ\",\"p\":\"xyDhGyOMvJrUGOJqX2O9kPZjj8YP9OmWwy-h0DJdZzwAV4buVLCRzTGd3nwfEcUNE9yh6li7A89YWFOTwEjj3V54JajAgAkkIZ0oKABoTRaRIvMRfVsye9QZNvBGGfKQwly23nRYIXjR-lmWWoPdldmvEYp3zUy6DiIhKup7XBc\",\"q\":\"vAjWS_3YEEK3LNn3h0nB5eDpEe12OOzL-Cx_Kmw8LiweFaejgE5zldwUcuJRlZbDQ-Ax5nBCu0bMvxPEEEDjO08OhqHCUDAllnpLO0aYojg8WytxWslyKIQ9ZpRhKpfUmtfaUl1eP6eqTxH5W5_1khrK-VjGQKDxNasEhHuIZfU\",\"dp\":\"hpSVLydepdWqhUr5A5FAfGnZrkD5Zdg9mZtmrHRtpijqPj2mdDyFvf3LqaOPyA26ofLax6zCcHfBSKjr0egxgNqpLyKXP7Ft5v31NtvXokofO1S2PFfXjdMyW2wWpNDIv2O0ADL3oV-r4pyLvo8iwnVGGf_QqkMx9_1fF0c0qm8\",\"dq\":\"JzfcomrmdrXDiMpJc2Ex3OVlF0Uk5EiXXkLBnzKF9sdi2vdlBazXNMl7Rl7nz0Brp6uKHNsLQA5LRAs2WIGAI22gxPnWEm2IWXNWX52g1izOgeF0ug_MDKFQQSXvgje6szUUJxusPbCVt_oyvSaGzJtj_E_EwdQPmzb5MTymvUU\",\"qi\":\"jJa3zcjDk5E0pa1JyuC_e58GC_dWzm_CAfbl75qcLrNUKGu_LOUQg5RwmJSRKVw475lahrP-tsN5Pp1mwk3D_YzBZp6oJqKYzhheU0Hq6zokqDe8JmSxAac040jqd-46LIDJccm8XpM1vx-Ep8F6Fxupn7-Ak5Xk4iRZ1_Aidqo\"}\n";

    /**
     * 生成token
     *
     * @param userId       用户id
     * @param username 用户名字
     * @return
     */
    @SneakyThrows
    public static String sign(Long userId, String username) {
        // 1、 创建jwtclaims  jwt内容载荷部分
        JwtClaims claims = new JwtClaims();
        // 是谁创建了令牌并且签署了它
        claims.setIssuer("malu");
        // 令牌将被发送给谁
        claims.setAudience("audience");
        // 失效时间长（分钟）
        claims.setExpirationTimeMinutesInTheFuture(60 * 24);
        // 令牌唯一标识符
        claims.setGeneratedJwtId();
        // 当令牌被发布或者创建
        claims.setIssuedAtToNow();
        // 再次之前令牌无效
        claims.setNotBeforeMinutesInThePast(2);
        // 主题
        claims.setSubject("shopping");
        // 可以添加关于这个主题得声明属性
        claims.setClaim("userId", userId);
        claims.setClaim("username", username);

        // 2、签名
        JsonWebSignature jws = new JsonWebSignature();
        //赋值载荷
        jws.setPayload(claims.toJson());

        // 3、jwt使用私钥签署
        PrivateKey privateKey = new RsaJsonWebKey(JsonUtil.parseJson(PRIVATE_JSON)).getPrivateKey();
        jws.setKey(privateKey);

        // 4、设置关键 kid
        jws.setKeyIdHeaderValue("keyId");

        // 5、设置签名算法
        jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
        // 6、生成jwt
        String jwt = jws.getCompactSerialization();
        return jwt;
    }


    /**
     * 解密token，获取token中的信息
     *
     * @param token
     */
    @SneakyThrows
    public static Map<String, Object> verify(String token){
        // 1、引入公钥
        PublicKey publicKey = new RsaJsonWebKey(JsonUtil.parseJson(PUBLIC_JSON)).getPublicKey();
        // 2、使用jwtcoonsumer  验证和处理jwt
        JwtConsumer jwtConsumer = new JwtConsumerBuilder()
                .setRequireExpirationTime() //过期时间
                .setAllowedClockSkewInSeconds(30) //允许在验证得时候留有一些余地 计算时钟偏差  秒
                .setRequireSubject() // 主题生命
                .setExpectedIssuer("malu") // jwt需要知道谁发布得 用来验证发布人
                .setExpectedAudience("audience") //jwt目的是谁 用来验证观众
                .setVerificationKey(publicKey) // 用公钥验证签名  验证密钥
                .setJwsAlgorithmConstraints(new AlgorithmConstraints(AlgorithmConstraints.ConstraintType.WHITELIST, AlgorithmIdentifiers.RSA_USING_SHA256))
                .build();
        // 3、验证jwt 并将其处理为 claims
        try {
            JwtClaims jwtClaims = jwtConsumer.processToClaims(token);
            return jwtClaims.getClaimsMap();
        }catch (Exception e){
            return new HashMap();
        }
    }


    public static void main(String[] args){
        // 生成
        String xx = sign(1001L, "malu");
        System.out.println(xx);

        Map<String, Object> stringObjectMap = verify(xx);
        System.out.println(stringObjectMap.get("userId"));
        System.out.println(stringObjectMap.get("username"));
    }
}